/*
 * Copyright (c) 2010-2013 Ruben Chakhmakhchyan. All rights reserved.
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Eclipse Public License
 * Version 1.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://opensource.org/licenses/EPL-1.0 and read it before using this file.
 */

#include "stdafx.h"
#include "CScriptableDeviceIndexer.h"
#include "CScriptableDevice.h"
#include "strings.h"
#include "convert.h"


#define INDEXBASE 10000L


CScriptableDeviceIndexer::CScriptableDeviceIndexer()
    : m_model( NULL )
{
}

CScriptableDeviceIndexer::~CScriptableDeviceIndexer()
{
}

STDMETHODIMP CScriptableDeviceIndexer::get_length( VARIANT* pVal )
{
    if ( m_model )
    {
        pVal->vt = VT_INT;
        pVal->intVal = m_model->getDeviceCount();
    }
    return S_OK;
}

STDMETHODIMP CScriptableDeviceIndexer::get_count( VARIANT* pVal )
{
    if ( m_model )
    {
        pVal->vt = VT_INT;
        pVal->intVal = m_model->getDeviceCount();
    }
    return S_OK;
}

STDMETHODIMP CScriptableDeviceIndexer::GetIDsOfNames( _In_ REFIID riid, _In_count_(cNames) _Deref_pre_z_ LPOLESTR* rgszNames, _In_ UINT cNames, _In_ LCID lcid, _Out_ DISPID* rgdispid )
{
    if ( cNames == 1 )
    {
        bool isIndex = false;
        int index = 0;
        wchar_t* name = rgszNames[ 0 ];

        bool is0 = String::Equal( L"0", name ) == 0;

        if ( is0 ) isIndex = true;
        else
        {
            if ( ( index = Convert::ToInt( name ) ) != 0 )
            {
                isIndex = true;
            }
        }

        if ( isIndex )
        {
            *rgdispid = INDEXBASE + ( LONG ) index;
            return S_OK;
        }
    }

    return BaseDispatch::GetIDsOfNames( riid, rgszNames, cNames, lcid, rgdispid );
}

STDMETHODIMP CScriptableDeviceIndexer::Invoke( _In_ DISPID dispidMember, _In_ REFIID riid, _In_ LCID lcid, _In_ WORD wFlags, _In_ DISPPARAMS* pdispparams, _Out_opt_ VARIANT* pvarResult, _Out_opt_ EXCEPINFO* pexcepinfo, _Out_opt_ UINT* puArgErr )
{
    if ( dispidMember >= INDEXBASE )
    {
        int index = ( int ) ( dispidMember - INDEXBASE );

        if ( index >= 0 && index < m_model->getDeviceCount() )
        {
            ImagingDevice* device = m_model->getDevice( index );
            void* tag = device->getTag();

            IDispatch* disp = NULL;
            if ( tag == NULL )
            {
                IUnknown* iu = NULL;
                if ( SUCCEEDED( ::CoCreateInstance( CLSID_ScriptableDevice, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, ( void** ) &iu ) ) )
                {
                    CScriptableDevice* i = static_cast<CScriptableDevice*>( iu );
                    i->setData( const_cast<ImagingDevice*>( device ) );
                    device->setEventHandler( i );
                    device->setTag( tag = iu );
                }
            }

            if ( tag )
            {
                IUnknown* iu = ( IUnknown* ) tag;
                if ( iu->QueryInterface( IID_IDispatch, ( void** ) &disp ) != S_OK )
                {
                    throw "cannot get device info disp!";
                }

                pvarResult->vt = VT_DISPATCH;
                pvarResult->pdispVal = disp;

                return S_OK;
            }
            else
            {
                return DISP_E_EXCEPTION;
            }
        }
        else
        {
            return DISP_E_MEMBERNOTFOUND;
        }
    }

    return BaseDispatch::Invoke( dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr );
}
